﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Lib
{
    public class Client: NetworkObj
    {
        private const int BUFFER_LENGTH = 2048;

        private Socket socket;
        private string ip;
        private int port;
        private byte[] tmp_buffer = new byte[BUFFER_LENGTH];
        private bool is_waiting_ok_signal = false;

        public delegate void ReceiveFunc(byte[] data);

        public ReceiveFunc OnReceive;

        public Client()
        {
        }

        public bool Connect(string ip, int port)
        {
            this.ip = ip;
            this.port = port;

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.Connect(new IPEndPoint(IPAddress.Parse(this.ip), this.port));
            socket.BeginReceive(tmp_buffer, 0, BUFFER_LENGTH, SocketFlags.None, new AsyncCallback(Receive), socket);

            return true;
        }

        private void Receive(IAsyncResult result)
        {
            Socket client = (Socket)result.AsyncState;
            int len = client.EndReceive(result);

            if (is_waiting_ok_signal)
            {
                is_waiting_ok_signal = false;
                client.BeginReceive(tmp_buffer, 0, BUFFER_LENGTH, SocketFlags.None, new AsyncCallback(Receive), socket);
            }
            else
            {
                if (OnReceive != null)
                {
                    byte[] bff = tmp_buffer.Take(len).ToArray();
                    OnReceive(bff);
                    client.BeginReceive(tmp_buffer, 0, BUFFER_LENGTH, SocketFlags.None, new AsyncCallback(Receive), socket);
                }
            }
        }

        private void Sent(IAsyncResult result)
        {
            Socket sock = (Socket)result.AsyncState;
            int len = socket.EndSend(result);
        }

        // Send data
        public void Send(byte[] buffer)
        {
            socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Sent), socket);
        }

        public void Send(string data)
        {
            byte[] buff = Helpper.GetBytes(data);
            Send(buff);
        }

        public void SendMessage(string toUser, string Mess)
        {
            string final = toUser + ":" + Mess;
            Send(final);
        }

        public void RequestList()
        {
            string message = "<~~~>";
            Send(message);
        }

        private static Client client = null;
        public static Client GetInstance() {
            if (client == null) client = new Client();
            return client;
        }

        public void ReceiveOk()
        {
            is_waiting_ok_signal = true;
        }
    }
}
